package jbeagle.concurrent.client;

import java.rmi.RemoteException;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;
import org.apache.log4j.NDC;

import jbeagle.concurrent.remote.ConcurrentEvaluationManager;
import jbeagle.core.FitnessFunction;
import jbeagle.core.Individual;

public class Evaluator implements Runnable {

	static Logger log = Logger.getLogger(Evaluator.class);
	
	private ConcurrentEvaluationManager evalMgr;
	
	private long timeout = 100;
	private String name;
	private int evalCount = 0;
	
	protected FitnessFunction fitnessF;
	
	public Evaluator(FitnessFunction f) {
		this(f, "unnamed");
	}
	
	public Evaluator(FitnessFunction f, String name) {
		setFitnessFunction(f);
		NDC.push(name);
	}
		
	public void setEvaluationManager(ConcurrentEvaluationManager mgr) {
		evalMgr = mgr;
	}
	
	public void setMaxWaitTimeMillis(long time) {
		timeout = time;
	}
	
	public long getMaxWaitTimeMillis() {
		return timeout;
	}
	
	public FitnessFunction getFitnessFunction() {
		return fitnessF;
	}

	public void setFitnessFunction(FitnessFunction ff) {
		fitnessF = ff;
	}
	
	@Override
	public void run() {
		log.info("Running.");
		Individual ind = null;
		
		if ( evalMgr == null ) {
			log.warn("No evaluation manager set.");
		} else {
			try {
				while ( evalMgr.hasMoreToEvaluate() ) {
					if ( timeout < 0 )
						ind = evalMgr.getNextToEvaluate();
					else
						ind = evalMgr.pollNextToEvaluate(timeout, TimeUnit.MILLISECONDS);
					
					if ( ind != null ) {
						fitnessF.evaluate(ind);
						evalCount++;
						evalMgr.setEvaluationComplete(ind);
					}
				}
			} catch (RemoteException re) {
				log.warn("Problem with remote evaluation manager: " + re);
			}
		}
		
		log.info("Stopping. Evaluated " + evalCount + " individuals.");
		NDC.remove();
	}

}
